package com.whalefin.service;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.whalefin.domain.Advertise;
import com.whalefin.domain.LeaveMessage;
import com.whalefin.domain.Reply;
import com.whalefin.domain.User;
import com.whalefin.persistence.AdvertiseMapper;
import com.whalefin.persistence.ReplyMapper;
import com.whalefin.persistence.UserMapper;
import com.whalefin.persistence.tools.PaginationUtils;
import com.whalefin.service.tools.ApplicationParams;
import com.whalefin.service.tools.BooleanResult;
import com.whalefin.service.tools.UploadTool;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.ResourceTransactionManager;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;


@Controller
public class AdvertiseService {

    @Autowired
    private AdvertiseMapper advertiseMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private ReplyMapper replyMapper;

    @Autowired
    ResourceTransactionManager transactionManager;

    /**
     * 发布广告
     * @param ad_title
     * @param ad_content
     * @param ad_pic
     * @param userId
     * @param lng
     * @param lat
     * @return
     * @throws java.io.IOException
     */
    @Transactional
    @RequestMapping(method = RequestMethod.POST,value = "/addAdvertise")
    public @ResponseBody
    BooleanResult addAdvertise(@RequestParam String ad_title,@RequestParam String ad_content,@RequestParam(required = false) MultipartFile ad_pic,
                                                        @RequestParam Integer userId,@RequestParam Double lng,@RequestParam Double lat,@RequestParam String schoolNum,@RequestParam String address,@RequestParam(required = false) Double width,@RequestParam(required = false) Double height) throws IOException {


        //事务开始
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        TransactionStatus status = transactionManager.getTransaction(def);

        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //查询所有广告按时间倒叙排列
        List<Advertise> advertiseList = advertiseMapper.queryAllAdvertise(schoolNum);
//        //查询所有用户
//        List<User> userList = userMapper.queryAllUser();

        if(ad_title ==null && "".equals(ad_title)){

            //当遇到异常时回滚status对象绑定的事务。
            transactionManager.rollback(status);
            return new BooleanResult(false,"广告标题不能为空!");
        }
        if(ad_content == null && "".equals(ad_content)){
            transactionManager.rollback(status);
            return new BooleanResult(false,"广告内容不能为空!");
        }

        Advertise advertise = new Advertise();//新建广告实例
        //组装广告数据
        advertise.setAd_title(ad_title);
        advertise.setAd_content(ad_content);
        if (ad_pic != null && ad_pic.getSize() > 0) {
            String fileName = StringUtils.isBlank(genFileName(ad_pic)) ? "": genFileName(ad_pic);
            FileCopyUtils.copy(ad_pic.getBytes(), new File(genFilePath(fileName)));
            advertise.setAd_pic(fileName);
        }else {
            advertise.setAd_pic("");
        }
        if(userId != null || "".equals(userId)){
            advertise.setUserId(userId);
        }else {
            advertise.setUserId(0);
        }
        advertise.setCreatetime(sdf.format(date));
        advertise.setStatus("显示");//为0显示,为1隐藏
        advertise.setLng(lng);
        advertise.setLat(lat);
        advertise.setSchoolNum(schoolNum);
        advertise.setWidth(width);
        advertise.setHeight(height);
        advertise.setAddress(address);

        //创建经纬度计算方法实例
        UploadTool uploadTool = new UploadTool();
        BooleanResult contents = uploadTool.uploadAdvertiseLocation(lng, lat, advertiseList);
        JSONArray list = JSON.parseArray(contents.getResultMap().get("distanceLessThan2").toString());//取到小于两公里内的用户集合
        int length = 0;
        for(Object obj : list){
            JSONObject json = JSONObject.parseObject(obj.toString());
            int user_id = Integer.parseInt(json.get("id").toString());
            SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
            Calendar cal1 = Calendar.getInstance();
            cal1.add(Calendar.DAY_OF_MONTH, 0);
            String today = sdf1.format(cal1.getTime());//当前时间例：2015-05-21 00:00:00
            Calendar cal2 = Calendar.getInstance();
            cal2.add(Calendar.DAY_OF_MONTH,1);
            String tomorrow = sdf1.format(cal2.getTime());//明天 2015-05-22 00:00:00
            List<Advertise> advertises = advertiseMapper.queryAdvertisesByUserId(user_id,today,tomorrow);//通过用户id,时间范围查询他们发布的广告
            length +=advertises.size();//广告总数
        }
//        if(length <= 10){//判断当天广告是否发布超过10条
            User user = userMapper.queryUserByUserId(userId);
            if(user != null ){
                Double money = user.getBalance();
                if(money >= 5.0){
                    int result = advertiseMapper.addAdvertise(advertise);//添加广告
                    if(result > 0){
                        //计费开始，如果计费失败,rollback，并返回计费失败消息
                        try {
                            //计费,广告发布成功，扣款5元
                            Double balance = money - 5.0;
                            userMapper.updateBalance(balance, userId);

                        }catch (Exception e){
                            e.printStackTrace();
                            transactionManager.rollback(status);
                            return new BooleanResult(false, "计费失败!");
                        }

                        //计费成功，提交status绑定的事务，并返回发布成功
                        transactionManager.commit(status);
                        return new BooleanResult(true,"广告发布成功!");
                    }else {

                        //添加广告失败，rollback
                        transactionManager.rollback(status);
                        return new BooleanResult(false,"广告发布失败!");
                    }
                }else {
                    return new BooleanResult(false,"余额不足，请充值");
                }

            }else {
                return new BooleanResult(false,"用户不存在");
            }

//        }else {
//
//            //广告超过十条，rollback
//            transactionManager.rollback(status);
//            return new BooleanResult(false,"广告发布已超过10条!");
//        }
    }


    /**
     * 广告列表
     * @param lng
     * @param lat
     * @return
     */
    @RequestMapping(method = RequestMethod.POST,value = "/advertiseList")
    public @ResponseBody
    BooleanResult advertiseList(@RequestParam Double lng,@RequestParam Double lat,@RequestParam String schoolNum,@RequestParam Integer pageNo,@RequestParam Integer pageSize){

        if (pageNo == null) {
            pageNo = 1;// 起始页
        } else if (pageNo <= 0) {
            pageNo = 1;
        }
        int totalCount = advertiseMapper.totalAdCount(schoolNum);
        int count = totalCount / pageSize;
        if(totalCount % pageSize > 0){
            count++;
        }
        if(pageNo >= count && count != 0){
            pageNo = count;
        }
        int startIndex = PaginationUtils.getStartIndex(pageNo, pageSize);
        //查询所有广告按时间倒叙排列
        List<Advertise> advertiseList = advertiseMapper.queryAllAdvertiseByPage(schoolNum,startIndex,pageSize);
        //查询所有用户
        List<User> userList = userMapper.queryAllUser();
        //查询所有广告
        List<Reply> replyList = replyMapper.queryAllReplyAd();
        List listAd = new ArrayList();
        if(advertiseList != null && advertiseList.size() > 0) {
            for (int i = 0; i < advertiseList.size(); i++) {
                Double adLng = advertiseList.get(i).getLng();
                Double adLat = advertiseList.get(i).getLat();

                BigDecimal lngFirst=new BigDecimal(Double.toString(lng));
                Double lngLocation=lngFirst.setScale(6,BigDecimal.ROUND_HALF_UP).doubleValue();//取后六位经度
                BigDecimal latFirst=new BigDecimal(Double.toString(lat));
                Double latLocation=latFirst.setScale(6,BigDecimal.ROUND_HALF_UP).doubleValue();//取后六位纬度

                Double a = rad(lngLocation) - rad(adLng);
                Double b = rad(latLocation) - rad(adLat);
                Double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(rad(lat)) * Math.cos(rad(adLat)) * Math.pow(Math.sin(b / 2), 2)));
                s = s * EARTH_RADIUS;

                //新建广告实例
                Advertise advertise = new Advertise();

                if(s < 5.0){
                    //留言信息
                    advertise.setId(advertiseList.get(i).getId());
                    advertise.setAd_title(advertiseList.get(i).getAd_title());
                    advertise.setAd_content(advertiseList.get(i).getAd_content());
                    advertise.setUserId(advertiseList.get(i).getUserId());
                    advertise.setAd_pic(advertiseList.get(i).getAd_pic());
                    advertise.setTotaluserId("");
                    advertise.setCreatetime("");
                    advertise.setIndexPage(0);
                    advertise.setPageSize(0);
                    advertise.setLat(advertiseList.get(i).getLat());
                    advertise.setLng(advertiseList.get(i).getLng());
                    //用户的信息(名字,距离)
                    User userMsg = new User();
                    for(int j=0;j<userList.size();j++){
                        if(userList.get(j).getId() == advertiseList.get(i).getUserId()){
                            userMsg.setId(userList.get(j).getId());
                            userMsg.setUsername(userList.get(j).getUsername());
                            userMsg.setLat(0.0);
                            userMsg.setLng(0.0);
                            userMsg.setPhoneNum("");
                            userMsg.setLoginPassword("");
                            userMsg.setCreatetime("");
                            userMsg.setGender("");
                            userMsg.setAddress("");
                            userMsg.setUserpic("");

                            UploadTool uploadTool = new UploadTool();
                            BooleanResult contents = uploadTool.uploadAdvertiseLocation(lng, lat, advertiseList);
                            JSONArray list = JSON.parseArray(contents.getResultMap().get("distanceAllList").toString());//取到所有用户集合
                            for(Object obj: list){
                                JSONObject json = JSONObject.parseObject(obj.toString());
                                int user_id = Integer.parseInt(json.get("id").toString());
                                if(user_id == advertiseList.get(i).getUserId()){
                                    userMsg.setDistance(Double.parseDouble(json.get("distance").toString()));
                                }
                            }
                            advertise.getUserList().add(userMsg);
                        }
                    }
                    //回复数
                    for(int x=0;x<replyList.size();x++){
                        if(advertiseList.get(i).getId() == replyList.get(x).getAdvertiseId() ){
                            //查询所有回复
                            int replyCount = replyMapper.queryReplyAdCount(advertiseList.get(i).getId());
                            advertise.setReplyNum(replyCount);//回复数
                        }
                    }
                    listAd.add(advertise);
                }
            }
        }
        BooleanResult booleanResult = new BooleanResult(true, "广告首页信息");
        booleanResult.getResultMap().put("listAd", listAd);
        return booleanResult;
    }


    /**
     * 广告详情
     * @param advertiseId
     * @param userId
     * @param lng
     * @param lat
     * @return
     */
    @RequestMapping(method = RequestMethod.POST,value = "/advertiseDetails")
    public @ResponseBody
    BooleanResult advertiseDetails(@RequestParam Integer advertiseId,@RequestParam Integer userId,@RequestParam Double lng,@RequestParam Double lat){
        List adDetailList = new ArrayList();//广告详情集合
        //根据广告id查询对应广告信息
        Advertise advertise = advertiseMapper.queryAdvertisesByAdvertiseId(advertiseId);
        Advertise advertiseMsg = new Advertise();
        int user_id = advertise.getUserId();//发布该广告的用户的id
        //通过用户id查询对应用户的信息
        User user = userMapper.queryUserByUserId(user_id);
        Double adLng = advertise.getLng();//广告的经度
        Double adLat = advertise.getLat();//广告的纬度
        //阅读留言用户的经纬度，截取后六位
        BigDecimal lngFirst=new BigDecimal(Double.toString(lng));
        Double lngLocation=lngFirst.setScale(6,BigDecimal.ROUND_HALF_UP).doubleValue();//取后六位经度
        BigDecimal latFirst=new BigDecimal(Double.toString(lat));
        Double latLocation=latFirst.setScale(6,BigDecimal.ROUND_HALF_UP).doubleValue();//取后六位纬度
        //计算发布留言人与阅读人的距离
        Double a = rad(lngLocation) - rad(adLng);
        Double b = rad(latLocation) - rad(adLat);
        Double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(rad(lat)) * Math.cos(rad(adLat)) * Math.pow(Math.sin(b / 2), 2)));
        s = s * EARTH_RADIUS;
        //用户数据
        User userMsg = new User();
        userMsg.setId(user.getId());
        userMsg.setUsername(user.getUsername());
        userMsg.setAddress(user.getAddress());
        if(user.getUserpic() != null){
            userMsg.setUserpic(user.getUserpic());
        }else {
            userMsg.setUserpic("");
        }
        userMsg.setDistance(s);
        userMsg.setCreatetime("");
        userMsg.setPhoneNum("");
        userMsg.setLoginPassword("");
        userMsg.setLat(0.0);
        userMsg.setLng(0.0);
        userMsg.setGender("");
        if(user.getBalance() != null){
            userMsg.setBalance(user.getBalance());
        }else {
            userMsg.setBalance(0.0);
        }
        userMsg.setIndexPage(0);
        userMsg.setPageSize(0);
        advertiseMsg.getUserList().add(userMsg);//--------把用户信息存入广告信息实例

        //广告数据
        advertiseMsg.setId(advertise.getId());
        advertiseMsg.setAd_title(advertise.getAd_title());
        advertiseMsg.setAd_content(advertise.getAd_content());
        advertiseMsg.setAd_pic(advertise.getAd_pic());
        advertiseMsg.setUserId(advertise.getUserId());
        advertiseMsg.setTotaluserId("");
        advertiseMsg.setCreatetime("");
        advertiseMsg.setLng(advertise.getLng());
        advertiseMsg.setLat(advertise.getLat());
        advertiseMsg.setPageSize(0);
        advertiseMsg.setIndexPage(0);
        advertiseMsg.setWidth(advertise.getWidth());
        advertiseMsg.setHeight(advertise.getHeight());
        advertiseMsg.setAddress(advertise.getAddress());
        String totalUserId = advertise.getTotaluserId();//已存在的阅读人id
        if(totalUserId == null || "".equals(totalUserId)){//没有阅读人则直接添加阅读人id
            advertiseMapper.updateTotalUserId(advertiseId, userId); //用户阅读留言,插入用户id，记录阅读数
        }else{
            String[] arr = totalUserId.split(",");//阅读人id数组
            advertiseMsg.setReadCount(arr.length);
            if (!Arrays.asList(arr).contains(userId.toString())) {//判断是否已存在阅读人的id
                advertiseMapper.updateTotalUserId(advertiseId, userId); //用户阅读留言,插入用户id，记录阅读数
            }
        }

        //评论回复数据
        List<Reply> replyList = replyMapper.queryReplyByAdvertiseId(advertiseId);
        if(replyList != null && replyList.size() > 0){
            for(int i=0;i<replyList.size();i++){
                int commentId = replyList.get(i).getUserId();//评论人的id
                int tagetUserId = replyList.get(i).getTargetUserId();//回复评论的人的id
                String content = replyList.get(i).getReplyContent();//评论内容(回复内容)
                String time = replyList.get(i).getCreatetime();//评论时间
                int adverId = replyList.get(i).getAdvertiseId();//广告id
                int replyId = replyList.get(i).getId();//评论id
                int leaveMessageId = replyList.get(i).getLeaveMessageId();
                Reply reply = new Reply();
                User commentUser = userMapper.queryUserByUserId(commentId);//发布评论的人的信息
                User targetUser = userMapper.queryUserByUserId(tagetUserId);//回复评论的人的信息 tagetUserId !=0才有回复评论人的信息
                reply.setId(replyId);
                reply.setUserId(commentId);
                reply.setReplyContent(content);
                reply.setCreatetime(time);
                reply.setAdvertiseId(adverId);
                reply.setLeaveMessageId(leaveMessageId);
                reply.setUserName(commentUser.getUsername());
                if(commentUser.getUserpic() != null){
                    reply.setUserPic(commentUser.getUserpic());
                }else {
                    reply.setUserPic("");
                }
                if(targetUser != null){
                    reply.setTargetUserId(targetUser.getId());//回复评论的人的id
                }else {
                    reply.setTargetUserId(0);
                }

                if(targetUser != null){//当tagetUserId=0，进行非空判断
                    reply.setTargetName(targetUser.getUsername());//回复评论的人的名字
                }else {
                    reply.setTargetName("");
                }
                advertiseMsg.getReplyList().add(reply);
            }
        }
        adDetailList.add(advertiseMsg);
        BooleanResult booleanResult = new BooleanResult(true,"广告详情");
        booleanResult.getResultMap().put("adDetailList",adDetailList);
        return booleanResult;
    }


    /**
     * 点击地图查询周边广告
     * @param lng
     * @param lat
     * @return
     */
    @RequestMapping(method = RequestMethod.POST,value = "/searchOtherAdvertise")
    public @ResponseBody BooleanResult searchOtherLeaveMsg(@RequestParam Double lng,@RequestParam Double lat){
        BigDecimal lngFirst=new BigDecimal(Double.toString(lng));
        Double lngLocation=lngFirst.setScale(6,BigDecimal.ROUND_HALF_UP).doubleValue();//取后六位经度
        BigDecimal latFirst=new BigDecimal(Double.toString(lat));
        Double latLocation=latFirst.setScale(6,BigDecimal.ROUND_HALF_UP).doubleValue();//取后六位纬度
        List<Advertise> advertiseList = advertiseMapper.queryAdvertise();
        Double msgLng = 0.0;
        Double msgLat = 0.0;
        List listAd = new ArrayList();

        if(advertiseList!= null &&advertiseList.size() > 0){
            for(int i=0;i<advertiseList.size();i++){
                Advertise advertise = new Advertise();
                SimpleDateFormat  df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                Date date = new Date();
                long day= 0;
                long hour= 0;
                long min= 0;
                try {
                    Date d1 = df.parse(df.format(date));
                    Date d2 = df.parse(advertiseList.get(i).getCreatetime());
                    long l=d1.getTime()-d2.getTime();
                    day=l/(24*60*60*1000);
                    hour=(l/(60*60*1000)-day*24);
                    min=((l/(60*1000))-day*24*60-hour*60);
                } catch (Exception e){

                }
                msgLng = advertiseList.get(i).getLng();
                msgLat = advertiseList.get(i).getLat();
                Double a = rad(lngLocation) - rad(msgLng);
                Double b = rad(latLocation) - rad(msgLat);
                Double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(rad(lat)) * Math.cos(rad(msgLat)) * Math.pow(Math.sin(b / 2), 2)));
                s = s*EARTH_RADIUS;
                s = Math.round(s * 10000.0) / 10000.0;
                if(s<10.0 && min < 15 && day == 0 && hour == 0){
                    advertise.setId(advertiseList.get(i).getId());
                    advertise.setAd_title("");
                    advertise.setAd_content("");
                    advertise.setAd_pic("");
                    advertise.setTotaluserId("");
                    advertise.setCreatetime("");
                    advertise.setStatus("");
                    advertise.setSchoolNum("");
                    advertise.setAddress("");
                    advertise.setWidth(0.0);
                    advertise.setHeight(0.0);
                    advertise.setLng(advertiseList.get(i).getLng());
                    advertise.setLat(advertiseList.get(i).getLat());
                    advertise.setUserId(advertiseList.get(i).getUserId());
                    listAd.add(advertise);
                }
            }

            BooleanResult booleanResult = new BooleanResult(true,"周边广告坐标");
            booleanResult.getResultMap().put("listAd",listAd);
            return booleanResult;
        }else {
            return new BooleanResult(false,"没有广告信息");
        }
    }

    private String genFilePath(String fileName) {
        return ApplicationParams.IMG_SAVE_FOLDER + fileName;
    }

    private String genFileName(MultipartFile file) {
        // 使用时间做文件的prefix，防止文件冲突;
        String prefix = String.valueOf(new Date().getTime());
        return prefix + "-" + UUID.randomUUID();
    }

    //计算地图上两点距离辅助方法
    private static final double EARTH_RADIUS = 6378.137;// 赤道半径(单位m)

    /**
     * 转化为弧度(rad)
     */
    private static double rad(double d) {
        return d * Math.PI / 180.0;
    }


    /**
     * 以下方法后台使用
     */

    //查询广告总数
    public int totalCountAd(){
        return advertiseMapper.totalCountAd();
    }

    //分页查询所有广告
    public List<Advertise> queryAllAdvertises(Integer indexPage,Integer pageSize){
        return advertiseMapper.queryAllAdvertises(indexPage,pageSize);
    }

//    //根据条件查询广告总数
    public int totalCountByCondition(Advertise advertise){
        return advertiseMapper.totalCountByCondition(advertise);
    }

    //根据条件查询广告
    public List<Advertise> queryAllAdvertiseByCondition(Advertise advertise){
        return advertiseMapper.queryAllAdvertiseByCondition(advertise);
    }

    //跟新广告状态
    public int updateStatus(Integer id,String status){
        return advertiseMapper.updateStatus(id,status);
    }
}